package com.luxk.db.tests;

import java.util.Random;
import java.util.zip.Deflater;

public class ByteStreamXOR {

	static int size = 4096;

	public void run() {

		byte[] org = new byte[size];
		byte[] befor = new byte[size];
		byte[] after = new byte[size];

		fill(org);

		System.arraycopy(org, 0, befor, 0, befor.length);
		System.arraycopy(org, 0, after, 0, after.length);

		Random rand = new Random(System.currentTimeMillis());

		int offset = rand.nextInt(size);
		int length = rand.nextInt(size - offset);
		for(int i = 0; i < length; i++) {
			after[offset + i] = (byte)rand.nextInt(Byte.MAX_VALUE);
		}

		xor(befor, after, offset, length);

		byte[] zipped = new byte[size];

		Deflater compresser = new Deflater();
		compresser.setInput(befor, offset, length);
		compresser.finish();
		int compressLength = compresser.deflate(zipped);

		System.out.println("offset: " + offset + " length: " + length); 
		System.out.println("zipped length " + length + " -> " + compressLength +
				"(" + (float)((float)length/befor.length)*100 + ")");

		xor(befor, after, offset, length);
		diff(org, befor);
	}

	public void fill(byte[] b) {
		Random rand = new Random(System.currentTimeMillis());
		rand.nextBytes(b);
	}

	public void xor(byte[] b1, byte[] b2, int off, int size) {
		assert(b1.length == b2.length);
		assert(b1.length >= off + size);

		for(int i = 0; i < size; i++) {
			b1[off+i] ^= b2[off+i];
		}
	}

	public void diff(byte[] b1, byte[] b2) {

		System.out.println("\ndiffs...");

		if (b1.length != b2.length) {
			System.out.println("b1.length(" + b1.length +
					") != b2.length(" + b2.length + ")");
		}

		for(int i = 0; i < Math.min(b1.length, b2.length); i++) {
			if (b1[i] != b2[i]) {
				System.out.println(i + ": " + b1[i] + " != " + b2[i]);
			}
		}
	}

	public static void main(String[] args) {
		ByteStreamXOR bxor = new ByteStreamXOR();
		bxor.run();

		int size = 8 * 1024;

		byte[] b = new byte[size];
		byte[] z = new byte[size];
		bxor.fill(b);

		String s = "Closes the compressor and discards any unprocessed input. This method should be called when the compressor is no longer being used, but will also be called automatically by the finalize() method. Once this method is called, the behavior of the Deflater object is undefined.";
		b = s.getBytes();

		Deflater compresser = new Deflater();
		compresser.setInput(b);
		compresser.finish();
		int compressLength = compresser.deflate(z);

		System.out.println("zipped length " + b.length + " -> " + compressLength +
				"(" + (float)((float)compressLength/b.length)*100 + ")");
	}

}
